#include "Parser.h"

/*
 *--------------------------------------------------------------------------------------
 *       Class:  Parser
 *      Method:  parse
 * Description:  Realiza o parseamento de um arquivo
 *--------------------------------------------------------------------------------------
 */
MemoryPtr Parser::parse(const string& filename)
{
    // Cria uma memória
    MemoryPtr mem(new Memory);

    ifstream ifs(filename.c_str());
    vstring buffer;
    int size = -1;

    // Enquanto existir mais padrões a serem lidos
    while(getPattern(ifs, buffer))
    {
        if(size == -1)
            size = buffer.size();

        // Garante padrões de mesmo tamanho
        if(size != (int) buffer.size())
            throw parseEx;

        // Cria um novo padrão
        PatternPtr pat(new Pattern(size, size));

        // Insere os valores do padrão
        for(int i = 0; i < size; i++)
            for(int j = 0; j < size; j++)
                pat->at(i, j) = (buffer[i][j] == '0') ? -1 : 1;

        // Insere o padrão na memória
        mem->push_back(pat);
    }

    return mem;
}

/*
 *--------------------------------------------------------------------------------------
 *       Class:  Parser
 *      Method:  getPattern
 * Description:  Recupera um padrão dado em um vetor de strings
 *--------------------------------------------------------------------------------------
 */
bool Parser::getPattern(ifstream& ifs, vstring& buffer)
{
    // Limpa o buffer
    buffer.clear();

    string line;
    int length = -1;

    // Tenta pegar linhas até encontrar uma que tenha algo
    while(getLine(ifs, line))
    {
        if(line.length() > 0)
        {
            // Adiciona a linha
            buffer.push_back(string(line));
            length = line.length();
            break;
        }
    }

    // Recupera linhas
    while(getLine(ifs, line))
    {
        // Se a linha estiver vazia e tiver completado o padrão, terminou
        if(line.empty() && length == (int) buffer.size())
            break;

        if(length != (int) line.length())
            throw parseEx;

        // Adiciona a linha
        buffer.push_back(string(line));
    }

    return !ifs.eof() || !buffer.empty();
}

/*
 *--------------------------------------------------------------------------------------
 *       Class:  Parser
 *      Method:  getLine
 * Description:  Recupera uma linha do arquivo
 *--------------------------------------------------------------------------------------
 */
bool Parser::getLine(ifstream& ifs, string& line)
{
    // Limpa a string
    line.clear();

    if(!ifs.eof())
    {
        // Pega uma linha e remove os espaços extras
        getline(ifs, line);
        trim(line);
    }

    return !ifs.eof() || !line.empty();
}
